/******************************************************************************
  Some simple Hisilicon Hi3531 video encode functions.

  Copyright (C), 2010-2011, Hisilicon Tech. Co., Ltd.
 ******************************************************************************
Modification:  2011-2 Created
 ******************************************************************************/

#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* End of #ifdef __cplusplus */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <math.h>
#include <unistd.h>
#include <signal.h>

#include "sample_comm.h"
#include "mytest.h"
const HI_U8 g_SOI[2] = {0xFF, 0xD8};
const HI_U8 g_EOI[2] = {0xFF, 0xD9};
static pthread_t gs_VencPid;
static SAMPLE_VENC_GETSTREAM_PARA_S gs_stPara;
static HI_S32 gs_s32SnapCnt = 0;
#define VIDEO_BUF_SIZE  (1024 * 300)
/******************************************************************************
 * function : Set venc memory location
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_MemConfig(HI_VOID)
{
	HI_S32 i = 0;
	HI_S32 s32Ret;

	HI_CHAR * pcMmzName;
	MPP_CHN_S stMppChnVENC;
	MPP_CHN_S stMppChnGRP;

	/* group, venc max chn is 64*/
	for(i=0;i<64;i++)
	{
		stMppChnGRP.enModId  = HI_ID_GROUP;
		stMppChnGRP.s32DevId = i;
		stMppChnGRP.s32ChnId = 0;

		stMppChnVENC.enModId = HI_ID_VENC;
		stMppChnVENC.s32DevId = 0;
		stMppChnVENC.s32ChnId = i;

		if(0 == (i%2))
		{
			pcMmzName = NULL;  
		}
		else
		{
			pcMmzName = "ddr1";
		}

		/*grp*/
		s32Ret = HI_MPI_SYS_SetMemConf(&stMppChnGRP,pcMmzName);
		if (HI_SUCCESS != s32Ret)
		{
			SAMPLE_PRT("HI_MPI_SYS_SetMemConf failed with %#x!\n", s32Ret);
			return HI_FAILURE;
		} 

		/*venc*/
		s32Ret = HI_MPI_SYS_SetMemConf(&stMppChnVENC,pcMmzName);
		if (HI_SUCCESS != s32Ret)
		{
			SAMPLE_PRT("HI_MPI_SYS_SetMemConf with %#x!\n", s32Ret);
			return HI_FAILURE;
		}
	}

	return HI_SUCCESS;
}

/******************************************************************************
 * function : venc bind vpss           
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_BindVpss(VENC_GRP GrpChn,VPSS_GRP VpssGrp,VPSS_CHN VpssChn)
{
	HI_S32 s32Ret = HI_SUCCESS;
	MPP_CHN_S stSrcChn;
	MPP_CHN_S stDestChn;

	stSrcChn.enModId = HI_ID_VPSS;
	stSrcChn.s32DevId = VpssGrp;
	stSrcChn.s32ChnId = VpssChn;

	stDestChn.enModId = HI_ID_GROUP;
	stDestChn.s32DevId = GrpChn;
	stDestChn.s32ChnId = 0;

	s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);
	if (s32Ret != HI_SUCCESS)
	{
		SAMPLE_PRT("failed with %#x!\n", s32Ret);
		return HI_FAILURE;
	}

	return s32Ret;
}

/******************************************************************************
 * function : venc unbind vpss           
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_UnBindVpss(VENC_GRP GrpChn,VPSS_GRP VpssGrp,VPSS_CHN VpssChn)
{
	HI_S32 s32Ret = HI_SUCCESS;
	MPP_CHN_S stSrcChn;
	MPP_CHN_S stDestChn;

	stSrcChn.enModId = HI_ID_VPSS;
	stSrcChn.s32DevId = VpssGrp;
	stSrcChn.s32ChnId = VpssChn;

	stDestChn.enModId = HI_ID_GROUP;
	stDestChn.s32DevId = GrpChn;
	stDestChn.s32ChnId = 0;

	s32Ret = HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
	if (s32Ret != HI_SUCCESS)
	{
		SAMPLE_PRT("failed with %#x!\n", s32Ret);
		return HI_FAILURE;
	}

	return s32Ret;
}

/******************************************************************************
 * funciton : get file postfix according palyload_type.
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_GetFilePostfix(PAYLOAD_TYPE_E enPayload, char *szFilePostfix)
{
	if (PT_H264 == enPayload)
	{
		strcpy(szFilePostfix, ".h264");
	}
	else if (PT_JPEG == enPayload)
	{
		strcpy(szFilePostfix, ".jpg");
	}
	else if (PT_MJPEG == enPayload)
	{
		strcpy(szFilePostfix, ".mjp");
	}
	else if (PT_MP4VIDEO == enPayload)
	{
		strcpy(szFilePostfix, ".mp4");
	}
	else
	{
		SAMPLE_PRT("payload type err!\n");
		return HI_FAILURE;
	}
	return HI_SUCCESS;
}

/******************************************************************************
 * funciton : save mjpeg stream. 
 * WARNING: in Hi3531, user needn't write SOI & EOI.
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_SaveMJpeg(FILE* fpJpegFile, VENC_STREAM_S *pstStream)
{
	VENC_PACK_S*  pstData;
	HI_U32 i;

	//fwrite(g_SOI, 1, sizeof(g_SOI), fpJpegFile); //in Hi3531, user needn't write SOI!

	for (i = 0; i < pstStream->u32PackCount; i++)
	{
		pstData = &pstStream->pstPack[i];
		fwrite(pstData->pu8Addr[0], pstData->u32Len[0], 1, fpJpegFile);
		fwrite(pstData->pu8Addr[1], pstData->u32Len[1], 1, fpJpegFile);
	}

	//fwrite(g_EOI, 1, sizeof(g_EOI), fpJpegFile);//in Hi3531, user needn't write SOI!

	return HI_SUCCESS;
}

/******************************************************************************
 * funciton : save H264 stream
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_SaveH264(FILE* fpH264File, VENC_STREAM_S *pstStream)
{
	HI_S32 i;


	for (i = 0; i < pstStream->u32PackCount; i++)
	{
		fwrite(pstStream->pstPack[i].pu8Addr[0],
				pstStream->pstPack[i].u32Len[0], 1, fpH264File);

		fflush(fpH264File);

		if (pstStream->pstPack[i].u32Len[1] > 0)
		{
			fwrite(pstStream->pstPack[i].pu8Addr[1],
					pstStream->pstPack[i].u32Len[1], 1, fpH264File);

			fflush(fpH264File);
		}
	}


	return HI_SUCCESS;
}

HI_S32 SAMPLE_COMM_VENC_SizeH264(FILE* fpH264File, VENC_STREAM_S *pstStream)
{
	HI_S32 i,len=0;


	for (i = 0; i < pstStream->u32PackCount; i++)
	{
		len+=pstStream->pstPack[i].u32Len[0];
		if (pstStream->pstPack[i].u32Len[1] > 0)
		{
			len+=pstStream->pstPack[i].u32Len[1];
		}
	}
	printf("len=%d\n",len);

	return HI_SUCCESS;
}



/******************************************************************************
 * funciton : save jpeg stream
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_SaveJPEG(FILE *fpJpegFile, VENC_STREAM_S *pstStream)
{
	VENC_PACK_S*  pstData;
	HI_U32 i;

	for (i = 0; i < pstStream->u32PackCount; i++)
	{
		pstData = &pstStream->pstPack[i];
		fwrite(pstData->pu8Addr[0], pstData->u32Len[0], 1, fpJpegFile);
		fwrite(pstData->pu8Addr[1], pstData->u32Len[1], 1, fpJpegFile);
	}

	return HI_SUCCESS;
}
/******************************************************************************
 * funciton : save snap stream
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_SaveSnap(VENC_STREAM_S *pstStream)
{
	char acFile[128]  = {0};
	FILE *pFile;
	HI_S32 s32Ret;

	sprintf(acFile, "snap_%d.jpg", gs_s32SnapCnt);
	pFile = fopen(acFile, "wb");
	if (pFile == NULL)
	{
		SAMPLE_PRT("open file err\n");
		return HI_FAILURE;
	}
	s32Ret = SAMPLE_COMM_VENC_SaveJPEG(pFile, pstStream);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("save snap picture failed!\n");
		return HI_FAILURE;
	}
	fclose(pFile);
	gs_s32SnapCnt++;
	return HI_SUCCESS;
}

/******************************************************************************
 * funciton : save stream
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_SaveStream(PAYLOAD_TYPE_E enType,FILE *pFd, VENC_STREAM_S *pstStream)
{
	HI_S32 s32Ret;

	if (PT_H264 == enType)
	{
		s32Ret = SAMPLE_COMM_VENC_SaveH264(pFd, pstStream);
	}
	else if (PT_MJPEG == enType)
	{
		s32Ret = SAMPLE_COMM_VENC_SaveMJpeg(pFd, pstStream);
	}
	else
	{
		return HI_FAILURE;
	}
	return s32Ret;
}

/******************************************************************************
 * funciton : Start venc stream mode (h264, mjpeg)
 * note      : rate control parameter need adjust, according your case.
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_Start(VENC_GRP VencGrp,VENC_CHN VencChn, PAYLOAD_TYPE_E enType, VIDEO_NORM_E enNorm, PIC_SIZE_E enSize, SAMPLE_RC_E enRcMode)
{
	HI_S32 s32Ret;
	VENC_CHN_ATTR_S stVencChnAttr;
	VENC_ATTR_H264_S stH264Attr;
	VENC_ATTR_H264_CBR_S    stH264Cbr;
	VENC_ATTR_H264_VBR_S    stH264Vbr;
	VENC_ATTR_H264_FIXQP_S  stH264FixQp;
	VENC_ATTR_MJPEG_S stMjpegAttr;
	VENC_ATTR_MJPEG_FIXQP_S stMjpegeFixQp;
	VENC_ATTR_JPEG_S stJpegAttr;
	SIZE_S stPicSize;

	s32Ret = SAMPLE_COMM_SYS_GetPicSize(enNorm, enSize, &stPicSize);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("Get picture size failed!\n");
		return HI_FAILURE;
	}
	/******************************************
	  step 1: Greate Venc Group
	 ******************************************/
	s32Ret = HI_MPI_VENC_CreateGroup(VencGrp);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_CreateGroup[%d] failed with %#x!\n",\
				VencGrp, s32Ret);
		return HI_FAILURE;
	}

	/******************************************
	  step 2:  Create Venc Channel
	 ******************************************/
	stVencChnAttr.stVeAttr.enType = enType;
	switch(enType)
	{
		case PT_H264:
			{
				stH264Attr.u32MaxPicWidth = stPicSize.u32Width;
				stH264Attr.u32MaxPicHeight = stPicSize.u32Height;
				stH264Attr.u32PicWidth = stPicSize.u32Width;/*the picture width*/
				stH264Attr.u32PicHeight = stPicSize.u32Height;/*the picture height*/
				stH264Attr.u32BufSize  = stPicSize.u32Width * stPicSize.u32Height * 2;/*stream buffer size*/
				stH264Attr.u32Profile  = 0;/*0: baseline; 1:MP; 2:HP   ? */
				stH264Attr.bByFrame = HI_TRUE;/*get stream mode is slice mode or frame mode?*/
				stH264Attr.bField = HI_FALSE;  /* surpport frame code only for hi3516, bfield = HI_FALSE */
				stH264Attr.bMainStream = HI_TRUE; /* surpport main stream only for hi3516, bMainStream = HI_TRUE */
				stH264Attr.u32Priority = 0; /*channels precedence level. invalidate for hi3516*/
				stH264Attr.bVIField = HI_FALSE;/*the sign of the VI picture is field or frame. Invalidate for hi3516*/
				memcpy(&stVencChnAttr.stVeAttr.stAttrH264e, &stH264Attr, sizeof(VENC_ATTR_H264_S));

				if(SAMPLE_RC_CBR == enRcMode)
				{
					stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
					stH264Cbr.u32Gop            = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;
					stH264Cbr.u32StatTime       = 1; /* stream rate statics time(s) */
					stH264Cbr.u32ViFrmRate      = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;/* input (vi) frame rate */
					stH264Cbr.fr32TargetFrmRate = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;/* target frame rate */
					stH264Cbr.fr32TargetFrmRate = 25;/* target frame rate */
					switch (enSize)
					{
						case PIC_QCIF:
							stH264Cbr.u32BitRate = 256; /* average bit rate */
							break;                       
						case PIC_QVGA:    /* 320 * 240 */
						case PIC_CIF:	
							stH264Cbr.u32BitRate = 512;
							stH264Cbr.fr32TargetFrmRate = 20;
							break;
						case PIC_D1:
						case PIC_VGA:	   /* 640 * 480 */
							stH264Cbr.u32BitRate = 512;

							break;
						case PIC_HD720:   /* 1280 * 720 */
							stH264Cbr.u32BitRate = 1024*1+512;

							break;
						case PIC_HD1080:  /* 1920 * 1080 */
							stH264Cbr.u32BitRate = 1024*4;
							break;
						default :
							stH264Cbr.u32BitRate = 1024;
							break;
					}

					//stH264Cbr.u32FluctuateLevel = 0; /* average bit rate */
					stH264Cbr.u32FluctuateLevel = 1; /* average bit rate */
					memcpy(&stVencChnAttr.stRcAttr.stAttrH264Cbr, &stH264Cbr, sizeof(VENC_ATTR_H264_CBR_S));
				}
				else if (SAMPLE_RC_FIXQP == enRcMode) 
				{
					stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264FIXQP;
					stH264FixQp.u32Gop = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;
					stH264FixQp.u32ViFrmRate = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;
					stH264FixQp.fr32TargetFrmRate = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;
					stH264FixQp.u32IQp = 20;
					stH264FixQp.u32PQp = 23;
					memcpy(&stVencChnAttr.stRcAttr.stAttrH264FixQp, &stH264FixQp,sizeof(VENC_ATTR_H264_FIXQP_S));
				}
				else if (SAMPLE_RC_VBR == enRcMode) 
				{
					stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264VBR;
					stH264Vbr.u32Gop = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;
					stH264Vbr.u32StatTime = 1;
					stH264Vbr.u32ViFrmRate = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;
					stH264Vbr.fr32TargetFrmRate = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;
					stH264Vbr.u32MinQp = 24;
					stH264Vbr.u32MaxQp = 32;
					switch (enSize)
					{
						case PIC_QCIF:
							stH264Vbr.u32MaxBitRate= 256*3; /* average bit rate */
							break;
						case PIC_QVGA:    /* 320 * 240 */
						case PIC_CIF:
							stH264Vbr.u32MaxBitRate = 512*3;
							break;
						case PIC_D1:
						case PIC_VGA:	   /* 640 * 480 */
							stH264Vbr.u32MaxBitRate = 1024*2*3;
							break;
						case PIC_HD720:   /* 1280 * 720 */
							stH264Vbr.u32MaxBitRate = 1024*3*3;
							break;
						case PIC_HD1080:  /* 1920 * 1080 */
							stH264Vbr.u32MaxBitRate = 1024*6*3;
							break;
						default :
							stH264Vbr.u32MaxBitRate = 1024*4*3;
							break;
					}
					memcpy(&stVencChnAttr.stRcAttr.stAttrH264Vbr, &stH264Vbr, sizeof(VENC_ATTR_H264_VBR_S));
				}
				else
				{
					return HI_FAILURE;
				}
			}
			break;

		case PT_MJPEG:
			{
				stMjpegAttr.u32MaxPicWidth = stPicSize.u32Width;
				stMjpegAttr.u32MaxPicHeight = stPicSize.u32Height;
				stMjpegAttr.u32PicWidth = stPicSize.u32Width;
				stMjpegAttr.u32PicHeight = stPicSize.u32Height;
				stMjpegAttr.u32BufSize = stPicSize.u32Width * stPicSize.u32Height * 2;
				stMjpegAttr.bByFrame = HI_TRUE;  /*get stream mode is field mode  or frame mode*/
				stMjpegAttr.bMainStream = HI_TRUE;  /*main stream or minor stream types?*/
				stMjpegAttr.bVIField = HI_FALSE;  /*the sign of the VI picture is field or frame?*/
				stMjpegAttr.u32Priority = 0;/*channels precedence level*/
				memcpy(&stVencChnAttr.stVeAttr.stAttrMjpeg, &stMjpegAttr, sizeof(VENC_ATTR_MJPEG_S));

				if(SAMPLE_RC_FIXQP == enRcMode)
				{
					stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_MJPEGFIXQP;
					stMjpegeFixQp.u32Qfactor        = 90;
					stMjpegeFixQp.u32ViFrmRate      = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;
					stMjpegeFixQp.fr32TargetFrmRate = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;
					memcpy(&stVencChnAttr.stRcAttr.stAttrMjpegeFixQp, &stMjpegeFixQp,
							sizeof(VENC_ATTR_MJPEG_FIXQP_S));
				}
				else if (SAMPLE_RC_CBR == enRcMode)
				{
					stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_MJPEGCBR;
					stVencChnAttr.stRcAttr.stAttrMjpegeCbr.u32StatTime       = 1;
					stVencChnAttr.stRcAttr.stAttrMjpegeCbr.u32ViFrmRate      = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;
					stVencChnAttr.stRcAttr.stAttrMjpegeCbr.fr32TargetFrmRate = (VIDEO_ENCODING_MODE_PAL== enNorm)?25:30;
					stVencChnAttr.stRcAttr.stAttrMjpegeCbr.u32FluctuateLevel = 0;
					switch (enSize)
					{
						case PIC_QCIF:
							stVencChnAttr.stRcAttr.stAttrMjpegeCbr.u32BitRate = 384*3; /* average bit rate */
							break;
						case PIC_QVGA:    /* 320 * 240 */
						case PIC_CIF:
							stVencChnAttr.stRcAttr.stAttrMjpegeCbr.u32BitRate = 768*3;
							break;
						case PIC_D1:
						case PIC_VGA:	   /* 640 * 480 */
							stVencChnAttr.stRcAttr.stAttrMjpegeCbr.u32BitRate = 1024*3*3;
							break;
						case PIC_HD720:   /* 1280 * 720 */
							stVencChnAttr.stRcAttr.stAttrMjpegeCbr.u32BitRate = 1024*5*3;
							break;
						case PIC_HD1080:  /* 1920 * 1080 */
							stVencChnAttr.stRcAttr.stAttrMjpegeCbr.u32BitRate = 1024*10*3;
							break;
						default :
							stVencChnAttr.stRcAttr.stAttrMjpegeCbr.u32BitRate = 1024*7*3;
							break;
					}
				}
				else if (SAMPLE_RC_VBR == enRcMode) 
				{
					stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_MJPEGVBR;
					stVencChnAttr.stRcAttr.stAttrMjpegeVbr.u32StatTime = 1;
					stVencChnAttr.stRcAttr.stAttrMjpegeVbr.u32ViFrmRate = (VIDEO_ENCODING_MODE_PAL == enNorm)?25:30;
					stVencChnAttr.stRcAttr.stAttrMjpegeVbr.fr32TargetFrmRate = 5;
					stVencChnAttr.stRcAttr.stAttrMjpegeVbr.u32MinQfactor = 50;
					stVencChnAttr.stRcAttr.stAttrMjpegeVbr.u32MaxQfactor = 95;
					switch (enSize)
					{
						case PIC_QCIF:
							stVencChnAttr.stRcAttr.stAttrMjpegeVbr.u32MaxBitRate= 256*3; /* average bit rate */
							break;
						case PIC_QVGA:    /* 320 * 240 */
						case PIC_CIF:
							stVencChnAttr.stRcAttr.stAttrMjpegeVbr.u32MaxBitRate = 512*3;
							break;
						case PIC_D1:
						case PIC_VGA:	   /* 640 * 480 */
							stVencChnAttr.stRcAttr.stAttrMjpegeVbr.u32MaxBitRate = 1024*2*3;
							break;
						case PIC_HD720:   /* 1280 * 720 */
							stVencChnAttr.stRcAttr.stAttrMjpegeVbr.u32MaxBitRate = 1024*3*3;
							break;
						case PIC_HD1080:  /* 1920 * 1080 */
							stVencChnAttr.stRcAttr.stAttrMjpegeVbr.u32MaxBitRate = 1024*6*3;
							break;
						default :
							stVencChnAttr.stRcAttr.stAttrMjpegeVbr.u32MaxBitRate = 1024*4*3;
							break;
					}
				}
				else 
				{
					SAMPLE_PRT("cann't support other mode in this version!\n");

					return HI_FAILURE;
				}
			}
			break;

		case PT_JPEG:
			stJpegAttr.u32PicWidth  = stPicSize.u32Width;
			stJpegAttr.u32PicHeight = stPicSize.u32Height;
			stJpegAttr.u32BufSize = stPicSize.u32Width * stPicSize.u32Height * 2;
			stJpegAttr.bByFrame = HI_TRUE;/*get stream mode is field mode  or frame mode*/
			stJpegAttr.bVIField = HI_FALSE;/*the sign of the VI picture is field or frame?*/
			stJpegAttr.u32Priority = 0;/*channels precedence level*/
			memcpy(&stVencChnAttr.stVeAttr.stAttrMjpeg, &stMjpegAttr, sizeof(VENC_ATTR_MJPEG_S));
			break;
		default:
			return HI_ERR_VENC_NOT_SUPPORT;
	}

	s32Ret = HI_MPI_VENC_CreateChn(VencChn, &stVencChnAttr);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_CreateChn [%d] faild with %#x!\n",\
				VencChn, s32Ret);
		return s32Ret;
	}

	/******************************************
	  step 3:  Regist Venc Channel to VencGrp
	 ******************************************/
	s32Ret = HI_MPI_VENC_RegisterChn(VencGrp, VencChn);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_RegisterChn faild with %#x!\n", s32Ret);
		return HI_FAILURE;
	}

	/******************************************
	  step 4:  Start Recv Venc Pictures
	 ******************************************/
	s32Ret = HI_MPI_VENC_StartRecvPic(VencChn);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_StartRecvPic faild with%#x!\n", s32Ret);
		return HI_FAILURE;
	}

	return HI_SUCCESS;

}

/******************************************************************************
 * funciton : Stop venc ( stream mode -- H264, MJPEG )
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_Stop(VENC_GRP VencGrp,VENC_CHN VencChn)
{
	HI_S32 s32Ret;

	/******************************************
	  step 1:  Stop Recv Pictures
	 ******************************************/
	s32Ret = HI_MPI_VENC_StopRecvPic(VencChn);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_StopRecvPic vechn[%d] failed with %#x!\n",\
				VencChn, s32Ret);
		return HI_FAILURE;
	}

	/******************************************
	  step 2:  UnRegist Venc Channel
	 ******************************************/
	s32Ret = HI_MPI_VENC_UnRegisterChn(VencChn);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_UnRegisterChn vechn[%d] failed with %#x!\n",\
				VencChn, s32Ret);
		return HI_FAILURE;
	}

	/******************************************
	  step 3:  Distroy Venc Channel
	 ******************************************/
	s32Ret = HI_MPI_VENC_DestroyChn(VencChn);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_DestroyChn vechn[%d] failed with %#x!\n",\
				VencChn, s32Ret);
		return HI_FAILURE;
	}

	/******************************************
	  step 4:  Distroy Venc Group
	 ******************************************/
	s32Ret = HI_MPI_VENC_DestroyGroup(VencGrp);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_DestroyGroup group[%d] failed with %#x!\n",\
				VencGrp, s32Ret);
		return HI_FAILURE;
	}

	return HI_SUCCESS;
}

/******************************************************************************
 * funciton : Start snap
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_SnapStart(VENC_GRP VencGrp,VENC_CHN VencChn, SIZE_S *pstSize)
{
	HI_S32 s32Ret;
	VENC_CHN_ATTR_S stVencChnAttr;
	VENC_ATTR_JPEG_S stJpegAttr;

	/******************************************
	  step 1: Greate Venc Group
	 ******************************************/
	s32Ret = HI_MPI_VENC_CreateGroup(VencGrp);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_CreateGroup[%d] failed with %#x!\n",\
				VencGrp, s32Ret);
		return HI_FAILURE;
	}

	/******************************************
	  step 2:  Create Venc Channel
	 ******************************************/
	stVencChnAttr.stVeAttr.enType = PT_JPEG;

	stJpegAttr.u32MaxPicWidth  = pstSize->u32Width;
	stJpegAttr.u32MaxPicHeight = pstSize->u32Height;
	stJpegAttr.u32PicWidth  = pstSize->u32Width;
	stJpegAttr.u32PicHeight = pstSize->u32Height;
	stJpegAttr.u32BufSize = pstSize->u32Width * pstSize->u32Height * 2;
	stJpegAttr.bByFrame = HI_TRUE;/*get stream mode is field mode  or frame mode*/
	stJpegAttr.bVIField = HI_FALSE;/*the sign of the VI picture is field or frame?*/
	stJpegAttr.u32Priority = 0;/*channels precedence level*/
	memcpy(&stVencChnAttr.stVeAttr.stAttrJpeg, &stJpegAttr, sizeof(VENC_ATTR_JPEG_S));

	s32Ret = HI_MPI_VENC_CreateChn(VencChn, &stVencChnAttr);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_CreateChn [%d] faild with %#x!\n",\
				VencChn, s32Ret);
		return s32Ret;
	}
	return HI_SUCCESS;
}

/******************************************************************************
 * funciton : Stop snap
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_SnapStop(VENC_GRP VencGrp,VENC_CHN VencChn)
{
	HI_S32 s32Ret;

	s32Ret = HI_MPI_VENC_DestroyChn(VencChn);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_DestroyChn vechn[%d] failed with %#x!\n", VencChn, s32Ret);
		return HI_FAILURE;
	}

	s32Ret = HI_MPI_VENC_DestroyGroup(VencGrp);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_DestroyGroup group[%d] failed with %#x!\n",\
				VencGrp, s32Ret);
		return HI_FAILURE;
	}

	return HI_SUCCESS;
}

/******************************************************************************
 * funciton : snap process
 ******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_SnapProcess(VENC_GRP VencGrp, VENC_CHN VencChn)
{
	struct timeval TimeoutVal;
	fd_set read_fds;
	HI_S32 s32VencFd;
	VENC_CHN_STAT_S stStat;
	VENC_STREAM_S stStream;
	HI_S32 s32Ret;

	/******************************************
	  step 1:  Regist Venc Channel to VencGrp
	 ******************************************/
	s32Ret = HI_MPI_VENC_RegisterChn(VencGrp, VencChn);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_RegisterChn faild with %#x!\n", s32Ret);
		return HI_FAILURE;
	}

	/******************************************
	  step 2:  Start Recv Venc Pictures
	 ******************************************/
	s32Ret = HI_MPI_VENC_StartRecvPic(VencChn);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VENC_StartRecvPic faild with%#x!\n", s32Ret);
		return HI_FAILURE;
	}
	/******************************************
	  step 3:  recv picture
	 ******************************************/
	s32VencFd = HI_MPI_VENC_GetFd(VencChn);
	if (s32VencFd < 0)
	{
		SAMPLE_PRT("HI_MPI_VENC_GetFd faild with%#x!\n", s32VencFd);
		return HI_FAILURE;
	}

	FD_ZERO(&read_fds);
	FD_SET(s32VencFd, &read_fds);

	TimeoutVal.tv_sec  = 2;
	TimeoutVal.tv_usec = 0;
	s32Ret = select(s32VencFd+1, &read_fds, NULL, NULL, &TimeoutVal);
	if (s32Ret < 0) 
	{
		SAMPLE_PRT("snap select failed!\n");
		return HI_FAILURE;
	}
	else if (0 == s32Ret) 
	{
		SAMPLE_PRT("snap time out!\n");
		return HI_FAILURE;
	}
	else
	{
		if (FD_ISSET(s32VencFd, &read_fds))
		{
			s32Ret = HI_MPI_VENC_Query(VencChn, &stStat);
			if (s32Ret != HI_SUCCESS)
			{
				SAMPLE_PRT("HI_MPI_VENC_Query failed with %#x!\n", s32Ret);
				return HI_FAILURE;
			}

			stStream.pstPack = (VENC_PACK_S*)malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks);
			if (NULL == stStream.pstPack)
			{
				SAMPLE_PRT("malloc memory failed!\n");
				return HI_FAILURE;
			}

			stStream.u32PackCount = stStat.u32CurPacks;
			s32Ret = HI_MPI_VENC_GetStream(VencChn, &stStream, HI_TRUE);
			if (HI_SUCCESS != s32Ret)
			{
				SAMPLE_PRT("HI_MPI_VENC_GetStream failed with %#x!\n", s32Ret);
				free(stStream.pstPack);
				stStream.pstPack = NULL;
				return HI_FAILURE;
			}

			s32Ret = SAMPLE_COMM_VENC_SaveSnap(&stStream);
			if (HI_SUCCESS != s32Ret)
			{
				SAMPLE_PRT("HI_MPI_VENC_GetStream failed with %#x!\n", s32Ret);
				free(stStream.pstPack);
				stStream.pstPack = NULL;
				return HI_FAILURE;
			}

			s32Ret = HI_MPI_VENC_ReleaseStream(VencChn, &stStream);
			if (s32Ret)
			{
				SAMPLE_PRT("HI_MPI_VENC_ReleaseStream failed with %#x!\n", s32Ret);
				free(stStream.pstPack);
				stStream.pstPack = NULL;
				return HI_FAILURE;
			}

			free(stStream.pstPack);
			stStream.pstPack = NULL;
		}
	}
	/******************************************
	  step 3:  stop recv picture
	 ******************************************/
	s32Ret = HI_MPI_VENC_StopRecvPic(VencChn);
	if (s32Ret != HI_SUCCESS)
	{
		SAMPLE_PRT("HI_MPI_VENC_StopRecvPic failed with %#x!\n",  s32Ret);
		return HI_FAILURE;
	}

	/******************************************
	  step 4:  UnRegister
	 ******************************************/
	s32Ret = HI_MPI_VENC_UnRegisterChn(VencChn);
	if (s32Ret != HI_SUCCESS)
	{
		SAMPLE_PRT("HI_MPI_VENC_UnRegisterChn failed with %#x!\n", s32Ret);
		return HI_FAILURE;
	}

	return HI_SUCCESS;
}

int fdarr[2];
unsigned int fd_chn[3];

HI_S32 HisiPutH264DataToBuffer(VENC_STREAM_S *pstStream, char *buf, int *size, int *frame_type)
{
	HI_S32 i,j;
	HI_S32 len=0,off=0,len2=2;
	unsigned char *pstr;
	int iframe=0;
	static unsigned int idx = 0;
	for (i = 0; i < pstStream->u32PackCount; i++)
	{
		len+=pstStream->pstPack[i].u32Len[0];

		if (pstStream->pstPack[i].u32Len[1] > 0)
		{
			len+=pstStream->pstPack[i].u32Len[1];
		}
	}

	for (i = 0; i < pstStream->u32PackCount; i++)
	{
		memcpy(buf+off,pstStream->pstPack[i].pu8Addr[0],pstStream->pstPack[i].u32Len[0]);
		off+=pstStream->pstPack[i].u32Len[0];
		pstr=pstStream->pstPack[i].pu8Addr[0];

		if(pstr[4]==0x67)
		{
			//UpdateSps(ringfifo[iput].buffer+off,9);
			iframe=1;
		}
		if(pstr[4]==0x68)
		{
			//UpdatePps(ringfifo[iput].buffer+off,4);
		}

		if (pstStream->pstPack[i].u32Len[1] > 0)
		{
			//memcpy(buf+off,pstStream->pstPack[i].pu8Addr[1], pstStream->pstPack[i].u32Len[1]);
			off+=pstStream->pstPack[i].u32Len[1];
		}
	}

	*size= len;
	*frame_type = iframe;
	//if(iframe)
	//{
	//	printf("get a I frame idx=%d, sz=%d\r\n", idx, len);
	//ringfifo[iput].frame_type = FRAME_TYPE_I;
	//}
	//else
	//	printf("get a P frame idx=%d, sz=%d\r\n", idx, len);

	idx ++;
	//ringfifo[iput].frame_type = FRAME_TYPE_P;
	//iput = addring(iput);
	//n++;

	return HI_SUCCESS;
}


extern unsigned int start_load;
//static unsigned int flagforstreamproc = 1;
static unsigned int flagforstart = 0;
/*
   void enable_stream()
   {
   flagforstreamproc = 0x1;
   SAMPLE_COMM_VENC_StartGetStream(1); 
   }

   void disable_stream()
   {
   flagforstreamproc = 0x0;
   }
 */
void start_stream()
{
	flagforstart = 0x1;
}

void stop_stream()
{
	flagforstart = 0x0;
}


unsigned int TO_USE_WHICH_CHANNEL = 0;
char bufer[VIDEO_BUF_SIZE];
unsigned int chnnel_1_enable = 0;
unsigned int chnnel_2_enable = 0;
unsigned int fd_chn0[2];
unsigned int fd_chn1[2];
unsigned int fd_chn2[2];
extern void *handle_one;
extern void *handle_two;
/******************************************************************************
 * funciton : get stream from each channels and save them
 ******************************************************************************/
HI_VOID* SAMPLE_COMM_VENC_GetVencStreamProc(HI_VOID *p)
{
	HI_S32 i;
	HI_S32 s32ChnTotal;
	VENC_CHN_ATTR_S stVencChnAttr;
	SAMPLE_VENC_GETSTREAM_PARA_S *pstPara;
	HI_S32 maxfd = 0;
	struct timeval TimeoutVal;
	fd_set read_fds;
	HI_S32 VencFd[VENC_MAX_CHN_NUM];
	HI_CHAR aszFileName[VENC_MAX_CHN_NUM][64];
	FILE *pFile[VENC_MAX_CHN_NUM];
	char szFilePostfix[10];
	VENC_CHN_STAT_S stStat;
	VENC_STREAM_S stStream;
	HI_S32 s32Ret;
	VENC_CHN VencChn;
	PAYLOAD_TYPE_E enPayLoadType[VENC_MAX_CHN_NUM];
	int jj=0;
	unsigned int sec=0;
	pstPara = (SAMPLE_VENC_GETSTREAM_PARA_S*)p;
	s32ChnTotal = pstPara->s32Cnt;
	BUFFERDATA_t mybuffer;	
	

	/******************************************
	  step 1:  check & prepare save-file & venc-fd
	 ******************************************/
	if (s32ChnTotal >= VENC_MAX_CHN_NUM)
	{
		SAMPLE_PRT("input count invaild\n");
		return NULL;
	}
	for (i = 0; i < s32ChnTotal; i++)
	{
		/* decide the stream file name, and open file to save stream */
		VencChn = i;
		s32Ret = HI_MPI_VENC_GetChnAttr(VencChn, &stVencChnAttr);
		if(s32Ret != HI_SUCCESS)
		{
			SAMPLE_PRT("HI_MPI_VENC_GetChnAttr chn[%d] failed with %#x!\n", \
					VencChn, s32Ret);
			return NULL;
		}
		enPayLoadType[i] = stVencChnAttr.stVeAttr.enType;

		s32Ret = SAMPLE_COMM_VENC_GetFilePostfix(enPayLoadType[i], szFilePostfix);
		if(s32Ret != HI_SUCCESS)
		{
			SAMPLE_PRT("SAMPLE_COMM_VENC_GetFilePostfix [%d] failed with %#x!\n", \
					stVencChnAttr.stVeAttr.enType, s32Ret);
			return NULL;
		}
		sprintf(aszFileName[i], "stream_chn%d%s", i, szFilePostfix);
		pFile[i] = fopen(aszFileName[i], "wb");
		if (!pFile[i])
		{
			SAMPLE_PRT("open file[%s] failed!\n", 
					aszFileName[i]);
			return NULL;
		}

		/* Set Venc Fd. */
		VencFd[i] = HI_MPI_VENC_GetFd(i);
		if (VencFd[i] < 0)
		{
			SAMPLE_PRT("HI_MPI_VENC_GetFd failed with %#x!\n", 
					VencFd[i]);
			return NULL;
		}
		if (maxfd <= VencFd[i])
		{
			maxfd = VencFd[i];
		}
	}

	/******************************************
	  step 2:  Start to get streams of each channel.
	 ******************************************/
	while (HI_TRUE == pstPara->bThreadStart)
	{
		FD_ZERO(&read_fds);
		for (i = 0; i < s32ChnTotal; i++)
		{
			FD_SET(VencFd[i], &read_fds);
		}

		TimeoutVal.tv_sec  = 2;
		TimeoutVal.tv_usec = 0;
		s32Ret = select(maxfd + 1, &read_fds, NULL, NULL, &TimeoutVal);
		if (s32Ret < 0)
		{
			SAMPLE_PRT("select failed!\n");
			break;
		}
		else if (s32Ret == 0)
		{
			SAMPLE_PRT("get venc stream time out, exit thread\n");
			continue;
		}
		else
		{
			for (i = 0; i < s32ChnTotal; i++)
			{
				if (FD_ISSET(VencFd[i], &read_fds))
				{
					/*******************************************************
					  step 2.1 : query how many packs in one-frame stream.
					 *******************************************************/
					memset(&stStream, 0, sizeof(stStream));
					s32Ret = HI_MPI_VENC_Query(i, &stStat);
					if (HI_SUCCESS != s32Ret)
					{
						SAMPLE_PRT("HI_MPI_VENC_Query chn[%d] failed with %#x!\n", i, s32Ret);
						break;
					}

					/*******************************************************
					  step 2.2 : malloc corresponding number of pack nodes.
					 *******************************************************/
					stStream.pstPack = (VENC_PACK_S*)malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks);
					if (NULL == stStream.pstPack)
					{
						SAMPLE_PRT("malloc stream pack failed!\n");
						break;
					}

					/*******************************************************
					  step 2.3 : call mpi to get one-frame stream
					 *******************************************************/
					stStream.u32PackCount = stStat.u32CurPacks;
					//printf("stStream.u32PackCount=%d\r\n", stStream.u32PackCount);
					s32Ret = HI_MPI_VENC_GetStream(i, &stStream, HI_TRUE);
					if (HI_SUCCESS != s32Ret)
					{
						free(stStream.pstPack);
						stStream.pstPack = NULL;
						SAMPLE_PRT("HI_MPI_VENC_GetStream failed with %#x!\n", \
								s32Ret);
						break;
					}

#if 1
					static unsigned int idx0 = 0;
					static unsigned int idx1 = 0;
					if (TO_USE_WHICH_CHANNEL == 0x0)
					{
						if (i == 0)
						{
						        BUFFERDATA_t *pTMP = create_myfifo();
							int my_size = 0;
							int my_type = 0;
                                                        HisiPutH264DataToBuffer(&stStream, bufer, &my_size, &my_type);
							pTMP->buf = (char *)malloc(my_size);
							if (pTMP->buf == NULL)
							{
							   perror("out of mem\r\n");
							}
							memcpy(pTMP->buf, bufer, my_size);
							pTMP->size = my_size;
							pTMP->ftype = my_type;
							add_ele(pTMP);
							//write(fd_chn0[1], &stStream, sizeof (stStream));
							//printf("write chn0\r\n");	
							//HI_MPI_VENC_ReleaseStream(0, &stStream);
						}
						else
						{
#if 0
							s32Ret = HI_MPI_VENC_ReleaseStream(1, &stStream);
							if (HI_SUCCESS != s32Ret)
							{
							    free(stStream.pstPack);
							    stStream.pstPack = NULL;
							    break;
							}
#endif
						}
					}
					else if (TO_USE_WHICH_CHANNEL == 0x1)
					{
						if (i == 1)
                                                {
                                                        BUFFERDATA_t *pTMP = create_myfifo();
                                                        int my_size = 0;
                                                        int my_type = 0;
                                                        HisiPutH264DataToBuffer(&stStream, bufer, &my_size, &my_type);
                                                        pTMP->buf = (char *)malloc(my_size);
                                                        if (pTMP->buf == NULL)
                                                        {
                                                           perror("out of mem\r\n");
                                                        }
                                                        memcpy(pTMP->buf, bufer, my_size);
                                                        pTMP->size = my_size;
                                                        pTMP->ftype = my_type;
                                                        add_ele(pTMP);
                                                        //printf("write chn1\r\n");   
                                                        //HI_MPI_VENC_ReleaseStream(, &stStream);
                                                }
					}

					s32Ret = HI_MPI_VENC_ReleaseStream(i, &stStream);
				        free(stStream.pstPack);
					stStream.pstPack = NULL;
#endif


#if 0
					if (chnnel_1_enable == 0x1 && i==1)
					{
						write(fd_chn1[1], &stStream, sizeof (stStream));
						printf("write chn1 \r\n");	
					}
					else if (chnnel_1_enable == 0x0 && i==1)
					{
						printf("write chn1 off\r\n");
						s32Ret = HI_MPI_VENC_ReleaseStream(i, &stStream);
						if (HI_SUCCESS != s32Ret)
						{
							free(stStream.pstPack);
							stStream.pstPack = NULL;
							break;
						}
					}

					if (chnnel_2_enable == 0x1 && i==2)
					{
						write(fd_chn2[1], &stStream, sizeof (stStream));
						printf("write chn2 \r\n");	
					}
					else if (chnnel_2_enable == 0x0 && i==2)
					{
						
					}

#endif

					/*******************************************************
					  step 2.4 : save frame to file
					 *******************************************************/
#if 0

					if (flagforstreamproc == 0x1)
					{	
						printf("record\r\n");
						s32Ret = SAMPLE_COMM_VENC_SaveStream(enPayLoadType[i], pFile[i], &stStream);
						if (HI_SUCCESS != s32Ret)
						{
							free(stStream.pstPack);
							stStream.pstPack = NULL;
							SAMPLE_PRT("save stream failed!\n");
							break;
						}
					}
#endif
					/*if(i==0)
					  {
					  jj++;
					  if(jj%25==0)
					  {
					  sec++;
					//SAMPLE_COMM_VENC_SizeH264( pFile[i], &stStream);
					printf("sec=%d\n",sec);

					}


					}*/

				}
			}
		}
	}

	/*******************************************************
	 * step 3 : close save-file
	 *******************************************************/
	for (i = 0; i < s32ChnTotal; i++)
	{
		fclose(pFile[i]);
	}

	return NULL;
}

/******************************************************************************
 * funciton : start get venc stream process thread
 ******************************************************************************/
HI_S32 StartGetStream(int num)
{
	gs_stPara.bThreadStart = HI_TRUE;
	gs_stPara.s32Cnt = 2;

	TO_USE_WHICH_CHANNEL = num;	
	printf("==============%d\r\n", num);	
	return pthread_create(&gs_VencPid, 0, SAMPLE_COMM_VENC_GetVencStreamProc, (HI_VOID*)&gs_stPara);
}

/******************************************************************************
 * funciton : stop get venc stream process.
 ******************************************************************************/
HI_S32 StopGetStream()
{
	if (HI_TRUE == gs_stPara.bThreadStart)
	{
		gs_stPara.bThreadStart = HI_FALSE;
		pthread_join(gs_VencPid, 0);
	}
	return HI_SUCCESS;
}

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
